﻿#include "FrameQueue.h"

/* 初始化FrameQueue，视频和音频keep_last设置为1，字幕设置为0 */
int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
    memset(f, 0, sizeof(FrameQueue));
    if (!(f->mutex = SDL_CreateMutex()))
    {
        return -1;
    }
    if (!(f->cond = SDL_CreateCond()))
    {
        return -1;
    }
    f->pktq = pktq;
    f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
    f->keep_last = !!keep_last;
    for (int i = 0; i < f->max_size; i++)
    {
        if (!(f->queue[i].frame = av_frame_alloc())) // 分配AVFrame结构体
        {
            return -1;
        }
    }
    return 0;
}

void frame_queue_destory(FrameQueue *f)
{
    for (int i = 0; i < f->max_size; i++)
    {
        Frame *vp = &f->queue[i];
        // 释放vp->frame对象
        av_frame_free(&vp->frame);
    }
    SDL_DestroyMutex(f->mutex);
    SDL_DestroyCond(f->cond);
}

void frame_queue_signal(FrameQueue *f)
{
    SDL_LockMutex(f->mutex);
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

//获取队列当前Frame, 在调用该函数前先调用frame_queue_nb_remaining确保有frame可读
Frame *frame_queue_peek(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}

//获取当前Frame的下一Frame, 此时要确保queue里面至少有2个Frame
//不管你什么时候调用，返回来肯定不是 NULL
Frame *frame_queue_peek_next(FrameQueue *f)
{
    return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
}

//获取last Frame
Frame *frame_queue_peek_last(FrameQueue *f)
{
    return &f->queue[f->rindex];
}

// 获取可写指针
Frame *frame_queue_peek_writable(FrameQueue *f)
{
    //等待直到我们有空间去写一个新帧
    SDL_LockMutex(f->mutex);
    //检查是否需要退出
    while (f->size >= f->max_size &&!f->pktq->abort_request)
    {
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    //检查是不是要退出
    if (f->pktq->abort_request)
    {
        return NULL;
    }

    return &f->queue[f->windex];
}

// 获取可读
Frame *frame_queue_peek_readable(FrameQueue *f)
{
    //等待直到有一个可读的帧
    SDL_LockMutex(f->mutex);
    while (f->size <= 0 && !f->pktq->abort_request)
    {
        SDL_CondWait(f->cond, f->mutex);
    }
    SDL_UnlockMutex(f->mutex);

    if (f->pktq->abort_request)
    {
        return NULL;
    }

    return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}

// 更新写指针
void frame_queue_push(FrameQueue *f)
{
    if (++f->windex == f->max_size)
    {
        f->windex = 0;
    }
    SDL_LockMutex(f->mutex);
    f->size++;
    SDL_CondSignal(f->cond);    // 当_readable在等待时则可以唤醒
    SDL_UnlockMutex(f->mutex);
}

//释放当前frame，并更新读索引rindex
void frame_queue_next(FrameQueue *f)
{
    if (f->keep_last && !f->rindex_shown)
    {
        f->rindex_shown = 1;
        return;
    }
//    av_frame_unref(&f->queue[f->rindex]);
    frame_queue_unref_item(&f->queue[f->rindex]);
    if (++f->rindex == f->max_size)
    {
        f->rindex = 0;
    }
    SDL_LockMutex(f->mutex);
    f->size--;
    SDL_CondSignal(f->cond);
    SDL_UnlockMutex(f->mutex);
}

//返回还没有播放的帧的数量
int frame_queue_nb_remaining(FrameQueue *f)
{
    return f->size - f->rindex_shown;
}

int frame_queue_last_pos(FrameQueue *f)
{
    Frame *fp = &f->queue[f->rindex];
    if (f->rindex_shown && fp->serial == f->pktq->serial)
    {
        if(fp)
        {
            return fp->pos;
        }
        else
        {
            return -1;
        }
    }
}

void frame_queue_unref_item(Frame *vp)
{
    av_frame_unref(vp->frame);	/* 释放数据 */
}





